package com.pig4cloud.pig.ads.controller.gdt;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.pig4cloud.pig.ads.gdt.service.GdtAdvertiserService;
import com.pig4cloud.pig.ads.pig.mapper.gdt.GdtAdvFundsMapper;
import com.pig4cloud.pig.ads.service.*;
import com.pig4cloud.pig.api.entity.*;
import com.pig4cloud.pig.api.vo.AdAccountAgentVo;
import com.pig4cloud.pig.api.vo.AdAccountAgentVo.Advertiser;
import com.pig4cloud.pig.common.core.constant.enums.PlatformTypeEnum;
import com.pig4cloud.pig.common.core.util.R;
import com.pig4cloud.pig.common.security.util.SecurityUtils;
import com.pig4cloud.pig.api.gdt.dto.GdtAdvertiserDailyReportReq;
import com.pig4cloud.pig.api.gdt.entity.GdtAdvFunds;
import com.pig4cloud.pig.api.gdt.entity.GdtAdvertiser;
import com.pig4cloud.pig.api.gdt.vo.GdtAdvSelectVo;
import com.pig4cloud.pig.api.gdt.vo.GdtAuthCodeReqVo;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.*;

/**
 * @广点通广告账户管理模块
 * @author zhuxm
 *
 */
@Log4j2
@RestController
@RequiredArgsConstructor
@RequestMapping("/gdt/adv")
@Api(value = "/gdt/adv", tags = "广点通广告账户管理模块")
public class GdtAdvController {

	private static final DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd").toFormatter();

	private final AdUserAdverService adUserAdverService;

	private final AdAdverAuthService adAdverAuthService;

	private final GdtAdvertiserService gdtAdvertiserService;

	private final AdvService advService;

	private final GdtAdvFundsMapper gdtAdvFundsMapper;

	private final AdAccountService adAccountService;

	private final AdAgentService adAgentService;



	@Value(value = "${gdt_client_id}") private String gdtClientId;

	@Value(value = "${gdt_secret}") private String gdtSecret;

	@Value(value = "${gdt_state}") private String gdtState;

	@Value(value = "${gdt_rediect_url}") private String gdtRediectUrl;

	@Value(value = "${gdt_auth_scope}") private String gdtAuthScope;

	@Value(value = "${gdt_auth_url}") private String gdtAuthUrl;

	@Value(value = "${gdt_account_type}") private String gdtAccountType;

	@Value(value = "${gdt_account_display_number}") private String gdtAccountDisplayNumber;

	public static String GDT_OPENAPI_STATE_SPLIT = "\\|";



	/**
	  *  查询自身账号列表
	 */
	@GetMapping("/list")
	public R getAdverList(String advertiserId) {
		List<Advertising> list = new ArrayList<>();
		Integer id = SecurityUtils.getUser().getId();

		List<String> adList = advService.getOwnerAdv(id, PlatformTypeEnum.GDT.getValue());
		if(adList == null || adList.size() == 0) {
			return R.ok(list);
		}
		return R.ok(gdtAdvertiserService.list(Wrappers.<GdtAdvertiser>query().lambda().and(wrapper -> wrapper.in(GdtAdvertiser::getAccountId, adList).or().in(GdtAdvertiser::getHousekeeper, adList)).and(StringUtils.isNotBlank(advertiserId), wrapper -> wrapper.eq(GdtAdvertiser::getAccountId, advertiserId).or().like(GdtAdvertiser::getCorporationName, advertiserId))));
	}


	/**
	  *  查询自身账号列表（带管家账户）
	 */
	@GetMapping("/selectList")
	public R getSelectList(String advertiserId) {

		List<AdAccount> adAccountList = adAccountService.list(Wrappers.<AdAccount>query().lambda()
				.and(wrapper -> wrapper.eq(AdAccount::getMediaCode, PlatformTypeEnum.GDT.getValue()))
				.and(wrapper -> wrapper.apply("FIND_IN_SET ("+SecurityUtils.getUser().getId()+", throw_user)"))
				.and(StringUtils.isNotBlank(advertiserId), wrapper -> wrapper.eq(AdAccount::getAdvertiserId, advertiserId).or().like(AdAccount::getAdvertiserName, advertiserId)));
		return R.ok(adAccountList);
	}

	public static List<GdtAdvSelectVo> getNewList(List<GdtAdvSelectVo> oldList) {
		HashMap<String, TreeSet<GdtAdvSelectVo>> tempMap = new HashMap<String, TreeSet<GdtAdvSelectVo>>();

		// 去掉重复的key
		for (GdtAdvSelectVo oldvo : oldList) {
			String advid = oldvo.getAccountId();
			// containsKey(Object key)该方法判断Map集合中是否包含指定的键名，如果包含返回true，不包含返回false
			// containsValue(Object
			// value)该方法判断Map集合中是否包含指定的键值，如果包含返回true，不包含返回false
			if (tempMap.containsKey(advid)) {
				GdtAdvSelectVo newvo = new GdtAdvSelectVo();
				newvo.setAccountId(advid);
				// 合并相同key的value
				newvo.getChildrenList().addAll(tempMap.get(advid));
				newvo.getChildrenList().addAll(oldvo.getChildrenList());
				// HashMap不允许key重复，当有key重复时，前面key对应的value值会被覆盖
				tempMap.put(advid, newvo.getChildrenList());
			} else {
				tempMap.put(advid, oldvo.getChildrenList());
			}
		}
		List<GdtAdvSelectVo> newList = new ArrayList<GdtAdvSelectVo>();
		for (Map.Entry<String, TreeSet<GdtAdvSelectVo>> entry : tempMap.entrySet()) {
			GdtAdvSelectVo newvo = new GdtAdvSelectVo();
			newvo.setAccountId(entry.getKey());
			newvo.setChildrenList(entry.getValue());
			newList.add(newvo);
        }
		return newList;
	}


	/**
	 * 获取广点通的请求地址
	 * https://developers.e.qq.com/oauth/authorize?client_id={0}&state={1}&scope={2}&account_type={3}&account_display_number={4}&redirect_uri={5}
	 */
	@GetMapping("/toauth")
	public R toauth() {
		if(StringUtils.isBlank(gdtAuthUrl)) {
			return R.failed("系统配置错误");
		}
		String realAuthUrl = gdtAuthUrl.replace("{0}", gdtClientId).replace("{1}", "" + SecurityUtils.getUser().getId()).replace("{2}", gdtAuthScope).replace("{3}", gdtAccountType)
				.replace("{4}", gdtAccountDisplayNumber).replace("{5}", urlEncode(gdtRediectUrl));
		return R.ok(realAuthUrl);
	}

	private String urlEncode(String str) {
		try {
			return URLEncoder.encode(str, "UTF-8");
		}
		catch (UnsupportedEncodingException e) {
			return null;
		}
	}



	@GetMapping("/audit")
	public R audit(GdtAuthCodeReqVo authVo) {
//		String clientId = authVo.getClient_id();
		String authorizationCode = authVo.getAuthorization_code();
		String stateVo = authVo.getState();

		if(StringUtils.isAnyBlank(authorizationCode, stateVo)) {
			return R.failed( "媒体回调缺失必要参数,请联系技术人员");
		}

		final String[] args = new String(Base64.getUrlDecoder().decode(stateVo), StandardCharsets.UTF_8).split("\\|");
		//无需校验
//		if(args.length != 3){
//			return R.failed( "授权URL配置state错误!");
//		}
		Integer userId = Integer.parseInt(args[1]);
		Integer agentId = Integer.parseInt(args[2]);

		authVo.setClient_id(gdtClientId);
		authVo.setClient_secret(gdtSecret);
		authVo.setUserId(userId);
		authVo.setRedirect_uri(gdtRediectUrl);
		authVo.setAgentId(agentId);

		List<Advertiser> advertiserList;
		try {
			advertiserList = gdtAdvertiserService.saveAuth(authVo);
		} catch (Exception e) {
			log.error("广点通授权失败", e);
			return R.failed("广点通授权失败:"+e.getMessage());
		}

		// 为广告账户设置代理
		AdAgent agent = adAgentService.getOne(Wrappers.<AdAgent>lambdaQuery().select(AdAgent::getAgentName).eq(AdAgent::getId, agentId).eq(AdAgent::getIsDelete, 0));
		if (null == agent) {
			return R.ok(null, "广点通授权成功，但设置的代理商无效");
		}
		AdAccountAgentVo adAccountAgentVo = new AdAccountAgentVo();
		adAccountAgentVo.setAgentId(args[2]);
		adAccountAgentVo.setAgentName(agent.getAgentName());
		adAccountAgentVo.setEffectiveTime(LocalDate.now().format(DATE_FORMATTER));
		adAccountAgentVo.setAdvertisers(advertiserList);
		List<String> list = adAccountService.batchAddAccountAgent(adAccountAgentVo, userId);

		return R.ok(list);
	}


	/**
	 * 广点通广告账号授权
	 */
	@GetMapping("/auth")
	public R adverAuthPage(AdAdverAuth adAuth) {
		String adAccount = adAuth.getAdvertiserId();
		if(StringUtils.isBlank(adAccount)) {
			return R.failed("请输入需要绑定的广告账户ID");
		}
		GdtAdvertiser advertising = gdtAdvertiserService.getById(adAccount);
		//不可申请管家账户
		if(advertising == null) {
			return R.failed("账号不存在，请联系管理员");
		}
		Integer userId = SecurityUtils.getUser().getId();
		AdUserAdver userAdver = adUserAdverService.getOne(Wrappers.<AdUserAdver>query().lambda().eq(AdUserAdver::getAdvertiserId, adAccount)
				.eq(AdUserAdver::getUserId, userId).eq(AdUserAdver::getPlatformId, PlatformTypeEnum.GDT.getValue()));
		if(userAdver != null) {
			return R.failed("该广告账户ID已绑定，请勿重复绑定");
		}

		List<AdAdverAuth> list = adAdverAuthService.list(Wrappers.<AdAdverAuth>query().lambda().eq(AdAdverAuth::getAdvertiserId, adAccount)
				.eq(AdAdverAuth::getCreateuser, userId).eq(AdAdverAuth::getPlatformId, PlatformTypeEnum.GDT.getValue()).eq(AdAdverAuth::getStatus, 0));
		if(list != null && list.size() > 0) {
			return R.failed("该广告账户ID还在申请授权中，请勿重复授权");
		}


		adAuth.setPlatformId(PlatformTypeEnum.GDT.getValue());
		adAuth.setCreateuser(userId);
		return R.ok(adAdverAuthService.save(adAuth));
	}


	/**
	 *  查询自身账号列表 包含余额信息
	 */
	@GetMapping("/page_with_fund")
	public R pagedAdversWithFund(Page page, String searchStr) {
		return gdtAdvertiserService.pagedAdversWithFund(page, searchStr);
	}

	/**
	 * 更新 预警值
	 */
	@GetMapping("/update_alert_value")
	public R updateAlertValue(GdtAdvFunds req){
		if (StringUtils.isBlank(req.getAccountId())) {
		    return R.failed("未提供广告账户");
		}
		GdtAdvFunds record = gdtAdvFundsMapper.selectById(req.getAccountId());
		if (req.getAlertFund() != null){
			record.setAlertFund(req.getAlertFund());
		}

		if (SqlHelper.retBool(gdtAdvFundsMapper.updateById(record))){
			return R.ok("更新成功");
		}else{
			return R.failed("更新失败");
		}
	}


	@GetMapping("/paged_daily_report")
	public R pagedDailyReport(GdtAdvertiserDailyReportReq req) {
		return gdtAdvertiserService.pagedDailyReport(req);
	}

	//更新日预算
	@GetMapping("/change_daily_budget")
	public R changeDailyBudget(String accountId, BigDecimal budget) {
		return gdtAdvertiserService.changeDailyBudget(accountId,budget);
	}

	//预约
	@GetMapping("/order_daily_budget")
	public R orderDailyBudget(String accountId, BigDecimal budget) {
		return gdtAdvertiserService.orderDailyBudget(accountId, budget);
	}

}
